package org.cerberus.platform.internal.impl;

import java.util.HashMap;
import java.util.Map;

import org.cerberus.platform.internal.domain.IComponentClass;
import org.cerberus.platform.internal.domain.IComponentClassAttribute;
import org.cerberus.platform.internal.domain.IComponentClassEvent;
import org.cerberus.platform.internal.domain.IComponentClassResource;

/**
 * @author  chu
 */
final class ComponentClass implements IComponentClass {

	private final String classID;
	private final boolean root;
	private final boolean modal;
	private final ComponentClass superClass;
	private final Class<?> javaClass;
	
	private IComponentClassAttribute[] attributes;
	private Map<String, IComponentClassAttribute> attributeMap;
	private IComponentClassAttribute[] resolvedAttributes;
	
	private IComponentClassResource[] resources;
	private IComponentClassEvent[] events;
	
	private boolean hasComponents;
	
	int instanceCount = 0;
	
	ComponentClass(ComponentClass superClass, 
			Class<?> javaClass, 
			String classID,
			boolean defaultVisible,
			boolean modal) {
		this.superClass = superClass;
		this.root = defaultVisible;
		this.modal = modal;
		this.javaClass = javaClass;
		this.classID = classID;
	}
	
	void defineAttributes(IComponentClassAttribute[] attributes) {
		if (this.attributes != null) {
			throw new ComponentClassException("Attributes already defined.");
		}
		if (attributes != null && attributes.length > 0) {
			this.attributes = attributes;
			this.attributeMap = new HashMap<String, IComponentClassAttribute>(attributes.length);
			for (int i = 0; i < attributes.length; i++) {
				ComponentClassAttribute attribute = ((ComponentClassAttribute)attributes[i]);
				attribute.defineIndex(i, superClass != null && superClass.attributes != null ? superClass.attributes.length+i : i);
				if (!hasComponents) {
					hasComponents = hasComponents || !attribute.getAttributeClass().isPrimitive();
				}
				
				attributeMap.put(attributes[i].getName(),  attributes[i]);
			}
		}
	}
	
	@Override
	public boolean isDeclared() {
		return true;
	}

	void defineEvents(IComponentClassEvent[] events) {
		this.events = events;
	}

	void defineResources(IComponentClassResource[] resources) {
		this.resources = resources;
	}

	@Override
	public IComponentClassEvent[] getDeclaredEvents() {
		return null;
	}
	
	@Override
	public IComponentClassEvent[] getEvents() {
		return null;
	}
	
	@Override
	public IComponentClassResource[] getResources() {
		return null;
	}
	
	@Override
	public boolean isArray() {
		//TODO check if necessary
		return false;
	}
	
	@Override
	public boolean isPrimitive() {
		// primitives has its own subclass where 
		// this method returns true
		return false;
	}
	
	@Override
	public boolean isRoot() {
		return root;
	}
	
	public IComponentClassAttribute getAttribute(String attributeName) {
		if (attributeMap == null) {
			return null;
		}
		IComponentClassAttribute attribute = attributeMap.get(attributeName);
		if (attribute == null && superClass != null) {
			return superClass.getAttribute(attributeName);
		}
		return attribute;
	}
	
	public IComponentClassAttribute[] getAttributes() {
		if (resolvedAttributes != null) {
			if (resolvedAttributes.length == 0) {
				return null;
			}
			return resolvedAttributes;
		}
		IComponentClassAttribute[] superAttributes = superClass != null ? superClass.getAttributes() : null;
		if (attributes == null && superAttributes == null) {
			resolvedAttributes = new IComponentClassAttribute[0];
		} else if (superAttributes == null) {
			resolvedAttributes = attributes;
		} else if (attributes == null) {
			resolvedAttributes = superAttributes;
		} else {
			resolvedAttributes = new IComponentClassAttribute[superAttributes.length + attributes.length];
			System.arraycopy(superAttributes, 0, resolvedAttributes, 0, superAttributes.length);
			System.arraycopy(attributes, 0, resolvedAttributes, superAttributes.length, attributes.length);
		}
		return getAttributes();
	}
	
	public IComponentClassResource[] getDeclaredResources() {
		return resources;
	}
	public IComponentClassAttribute[] getDeclaredAttributes() {
		return attributes;
	}
	public int getAttributeCount() {
		if (superClass != null) {
			return superClass.getAttributeCount() + attributes.length;
		}
		return attributes.length;
	}
	
	public String getClassID() {
		return classID;
	}

	public ComponentClass getSuperClass() {
		return superClass;
	}
	
	
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder.append(getClassID());
		if (superClass != null) {
			builder.append(" extends "+superClass.getClassID());
		}
		builder.append(" {\n");
		for (int i = 0; i < getAttributes().length; i++) {
			IComponentClassAttribute attribute = getAttributes()[i];
			builder.append("  ").append(attribute);
			builder.append("\n");
		}
		builder.append("}");
		return builder.toString();
	}
	
	
}
